﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports; // For serial port communication
using System.Windows.Forms; // For messgage box
using DatabaseHelper;

namespace RS232
{
    public class RS232Reader
    {

        #region PRIVATE PROPERTIES
        private string _stringFormat;
        #endregion

        #region PUBLIC PROPERTIES
        public SerialPort Port { get; set; }
        public string StringName { get; set; }
        public string StringFormat
        {
            get
            {
                return _stringFormat;
            }
            set
            {
                _stringFormat = value;

                // Create list data fields with name from string format
                lstDataFields = new List<DataField>();
                string[] words = value.Split(',');
                foreach (string str in words)
                {
                    DataField dtf = new DataField(str, "");
                    lstDataFields.Add(dtf);
                }
            }
        }
        public bool IsOpen { get; set; }
        public bool IsLogging { get; set; }
        public string RecordID { get; set; }
        public string strAllFields { get; private set; }
        public List<DataField> lstDataFields { get; private set; }
        #endregion

        #region CONSTRUCTORS

        public RS232Reader()
        {
            Port = new SerialPort();
            StringName = "";
            StringFormat = "";
            IsOpen = false;
            IsLogging = false;
            RecordID = "0";
            strAllFields = "";
            lstDataFields = new List<DataField>();
        }

        public RS232Reader(string portName, int baudRate, string name, string format)
            : this()
        {
            Port.PortName = portName;
            Port.BaudRate = baudRate;
            StringName = name;
            StringFormat = format;
        }
        #endregion

        #region EVENTS
        private System.Windows.Forms.Timer timerOpen = new System.Windows.Forms.Timer();
        private System.Timers.Timer timerLog = new System.Timers.Timer();

        public event EventHandler<RS232DataReceivedEventArgs> RS232DataReceived;

        protected virtual void OnRS232DataReceived(RS232DataReceivedEventArgs e)
        {
            EventHandler<RS232DataReceivedEventArgs> handler = RS232DataReceived;
            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion

        #region EVENT HANDLERS

        public void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            if (sp.IsOpen)
            {
                try
                {
                    string str = sp.ReadLine();
                    strAllFields = str;
                    string[] values = strAllFields.Split(',');
                    string[] names = StringFormat.Split(',');
                    int minLength = values.Length;
                    if (minLength > names.Length)
                    {
                        minLength = names.Length;
                    }
                    for (int i = 0; i < minLength; i++)
                    {
                        lstDataFields[i].Name = names[i];
                        lstDataFields[i].Value = values[i];
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

        private void timerOpen_Tick(object sender, EventArgs e)
        {
            RS232DataReceivedEventArgs args = new RS232DataReceivedEventArgs();
            args.AllFieldsString = strAllFields;
            args.Data = ToPData(lstDataFields);
            // Raise event and pass argument
            OnRS232DataReceived(args);
        }

        private void timerLog_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            DBHelper dh = new DBHelper();
            try
            {
                dh.Add(ToPData(lstDataFields), RecordID);
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.ToString());
            }
        }

        #endregion

        #region PRIVATE METHODS
        private PData ToPData(List<DataField> list)
        {
            PData pdt = new PData();
            foreach (DataField dtf in list)
            {
                switch (dtf.Name)
                {
                    case "KP": pdt.KP = dtf.Value; break;
                    case "kP": pdt.KP = dtf.Value; break;
                    case "Kp": pdt.KP = dtf.Value; break;
                    case "kp": pdt.KP = dtf.Value; break;

                    case "Easting": pdt.Easting = dtf.Value; break;
                    case "easting": pdt.Easting = dtf.Value; break;
                    case "EASTING": pdt.Easting = dtf.Value; break;
                    case "East": pdt.Easting = dtf.Value; break;
                    case "east": pdt.Easting = dtf.Value; break;
                    case "E": pdt.Easting = dtf.Value; break;
                    case "e": pdt.Easting = dtf.Value; break;

                    case "Northing": pdt.Northing = dtf.Value; break;
                    case "northing": pdt.Northing = dtf.Value; break;
                    case "NORTHING": pdt.Northing = dtf.Value; break;
                    case "North": pdt.Northing = dtf.Value; break;
                    case "north": pdt.Northing = dtf.Value; break;
                    case "N": pdt.Northing = dtf.Value; break;
                    case "n": pdt.Northing = dtf.Value; break;

                    case "CP": pdt.CP = dtf.Value; break;
                    case "cP": pdt.CP = dtf.Value; break;
                    case "cp": pdt.CP = dtf.Value; break;
                    case "Cp": pdt.CP = dtf.Value; break;
                    default: break;
                }
            }
            return pdt;
        }
        #endregion

        #region PUBLIC METHODS
        public bool Open()
        {
            Port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Port_DataReceived);
            if (!Port.IsOpen)
            {
                try
                {
                    Port.Open();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                    IsOpen = false;
                    return false;
                }
            }

            if (Port.IsOpen)
            {
                timerOpen.Interval = 1000;
                timerOpen.Tick += new EventHandler(timerOpen_Tick);
                timerOpen.Start();
            }
            // TO HERE mean SUCCESSFULLY
            IsOpen = true;
            return true;
        }

        public bool Close()
        {
            if (Port.IsOpen)
            {
                try
                {
                    Port.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(Port_DataReceived);
                    Port.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                    IsOpen = true;
                    return false;
                }
            }

            timerOpen.Stop();
            // TO HERE mean SUCCESSFULLY
            IsOpen = false;
            return true;
        }

        public void StartLogging(string recID)
        {
            RecordID = recID;
            if (!IsOpen)
            {
                Open();
            }
            timerLog.Interval = 1000;
            timerLog.Elapsed += new System.Timers.ElapsedEventHandler(timerLog_Elapsed);
            timerLog.Start();
            IsLogging = true;
        }

        public void StopLogging()
        {
            if (IsLogging)
            {
                timerLog.Stop();
                IsLogging = false;
            }
        }
        #endregion
    }
}
